/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { FileUtil, HvigorNode } from '@ohos/hvigor';
import { OhosHapContext, OhosHarContext, OhosHspContext, Target } from '@ohos/hvigor-ohos-plugin';
import { HMRouterPluginConfig } from './HMRouterPluginConfig';
import { HMRouterHvigorPlugin } from './HMRouterHvigorPlugin';
import { Logger } from './common/Logger';
import { HMRouterPluginConstant } from './common/Constant';
import { RouterInfo } from './common/PluginModel';

// HMRouterPluginHandle类，用于处理HMRouter插件
export class HMRouterPluginHandle {
  // 节点
  private readonly node: HvigorNode;
  // 模块上下文
  private readonly moduleContext: OhosHapContext | OhosHarContext | OhosHspContext;
  // 配置
  public readonly config: HMRouterPluginConfig;
  // 插件
  private readonly plugin: HMRouterHvigorPlugin;

  // 构造函数，初始化节点、模块上下文、配置和插件
  constructor(node: HvigorNode, moduleContext: OhosHapContext | OhosHarContext | OhosHspContext) {
    this.node = node;
    this.moduleContext = moduleContext;
    this.config = this.readConfig();
    this.plugin = new HMRouterHvigorPlugin(this.config);
  }

  // 启动插件
  public start() {
    Logger.info(
      `Exec ${this.moduleContext.getModuleType()}Plugin..., node:${this.node.getNodeName()}, nodePath:${this.node.getNodePath()}`
    );
    this.moduleContext.targets((target: Target) => {
      const targetName = target.getTargetName();
      this.node.registerTask({
        name: `${targetName}@HMRouterPluginTask`,
        run: () => {
          this.taskExec();
        },
        dependencies: [`${targetName}@PreBuild`],
        postDependencies: [`${targetName}@MergeProfile`],
      });
      this.node.registerTask({
        name: `${targetName}@CopyRouterMapToRawFileTask`,
        run: () => {
          this.copyRouterMapToRawFileTask(target.getBuildTargetOutputPath(), targetName);
        },
        dependencies: [`${targetName}@ProcessRouterMap`],
        postDependencies: [`${targetName}@ProcessResource`],
      });
    });
  }

  // 拷贝routerMap到raw文件
  private copyRouterMapToRawFileTask(buildOutputPath: string, targetName: string) {
    let routerMapFilePath = FileUtil.pathResolve(
      buildOutputPath,
      HMRouterPluginConstant.TEMP_ROUTER_MAP_PATH,
      targetName,
      HMRouterPluginConstant.ROUTER_MAP_NAME
    );
    let rawFilePath = this.config.getRawFilePath();
    FileUtil.ensureFileSync(rawFilePath);
    FileUtil.copyFileSync(routerMapFilePath, rawFilePath);
  }

  // 执行任务
  private taskExec() {
    let startTime = Date.now();
    Logger.info(this.node.getNodeName() + ': HMRouterPluginTask start');
    // 分析注解
    this.plugin.analyzeAnnotation();
    // 更新module.json
    this.updateModuleJsonOpt();
    // 更新profile
    this.updateBuildProfileOpt();
    let endTime = Date.now();
    Logger.info(this.config.moduleName + ': HMRouterPluginTask end');
    Logger.info(this.config.moduleName + ': HMRouterPluginTask cost: ' + (endTime - startTime) + ' ms');
  }

  // 更新module.json
  private updateModuleJsonOpt() {
    // 获取模块的json配置
    const moduleJsonOpt = this.moduleContext.getModuleJsonOpt();
    // 如果模块的json配置中有routerMap
    if (moduleJsonOpt.module.routerMap) {
      // 获取routerMap的文件名
      let routerMapFileName = moduleJsonOpt.module.routerMap.split(':')[1];
      // 获取routerMap的文件路径
      let routerMapFilePath = this.config.getModuleRouterMapFilePath(routerMapFileName);
      // 读取routerMap的json文件
      let routerMapObj = FileUtil.readJson5(routerMapFilePath);
      // 将routerMap添加到plugin的routerMap中
      this.plugin.routerMap.unshift(...((routerMapObj as any)['routerMap'] as Array<RouterInfo>));
    }
    // 生成routerMap
    this.plugin.generateRouterMap();
    // 将routerMap的名称设置为MODULE_ROUTER_MAP_NAME
    moduleJsonOpt.module.routerMap = HMRouterPluginConstant.MODULE_ROUTER_MAP_NAME;
    // 将修改后的moduleJsonOpt设置到moduleContext中
    this.moduleContext.setModuleJsonOpt(moduleJsonOpt);
  }

  private updateBuildProfileOpt() {
    // 获取构建配置选项
    const buildProfileOpt = this.moduleContext.getBuildProfileOpt();
    // 初始化 arkOptions 和 runtimeOnly 配置
    if (!buildProfileOpt.buildOption) {
      buildProfileOpt.buildOption = {};
    }
    if (!buildProfileOpt.buildOption.arkOptions) {
      buildProfileOpt.buildOption.arkOptions = {};
    }
    if (!buildProfileOpt.buildOption.arkOptions.runtimeOnly) {
      buildProfileOpt.buildOption.arkOptions.runtimeOnly = {};
    }
    if (!buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources) {
      buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources = [];
    }
    // 将路由信息推送到构建配置选项中
    this.pushRouterInfo(buildProfileOpt, this.plugin.routerMap);
    // 将构建配置选项设置到moduleContext中
    this.moduleContext.setBuildProfileOpt(buildProfileOpt);
  }

  // 将路由信息添加到 buildProfileOpt 中
  private pushRouterInfo(buildProfileOpt: any, routerMap: Array<RouterInfo>) {
    const sources = buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources;
    routerMap.forEach((item: RouterInfo) => {
      const name = item.name;
      if (
        name.includes(HMRouterPluginConstant.LIFECYCLE_PREFIX) ||
        name.includes(HMRouterPluginConstant.INTERCEPTOR_PREFIX) ||
        name.includes(HMRouterPluginConstant.ANIMATOR_PREFIX) ||
        name.includes(HMRouterPluginConstant.SERVICE_PREFIX)
      ) {
        sources.push('./' + item.pageSourceFile);
      }
    });
  }

  // 读取配置
  private readConfig(): HMRouterPluginConfig {
    let levels = 0;
    let configParam = {};
    while (levels < 4) {
      let configFilePath = FileUtil.pathResolve(
        this.node.getNodePath(),
        HMRouterPluginConstant.PARENT_DELIMITER.repeat(levels) + HMRouterPluginConstant.CONFIG_FILE_NAME
      );
      if (FileUtil.exist(configFilePath)) {
        configParam = FileUtil.readJson5(configFilePath);
        break;
      }
      levels++;
    }
    return new HMRouterPluginConfig(this.node.getNodeName(), this.node.getNodePath(), configParam);
  }
}
